﻿module Wrapper

open System

(* Wrapper for testing *)

(* for future use:
let inputBinMatrix = 
    printfn "Enter width of binary matrix:"
    let width = int( Console.ReadLine() )
    printfn "Enter height of binary matrix:"
    let height = int( Console.ReadLine() )
    
    printfn "Enter Binary Matrix:"
    // let s = System.Console.ReadLine()
    // (binOut : int [,])
    // 
    // Console.ReadLine() |> [,]
    let seq = Seq.initInfinite (fun _ -> Console.ReadLine()) 
    let binOut = array2D seq
    binOut *)

let testGiftWrap = 
        [| (0,0);
           (1,0);
           (1,1);
           (2,1);
           (2,2);
           (3,2);
           (3,1);
           (4,1);
           (4,2);
           (5,2);
           (5,0);
           (6,0);
           (6,2);
           (7,2);
           (7,3);
           (6,3);
           (6,4);
           (7,4);
           (7,5);
           (0,5);
        |]

let testCreateTiles = 
           [|
            [|(5,4);(5,0);(0,0);(0,4)|]
            [|(0,9);(5,5);(5,9);(0,5)|]
            [|(6,6);(6,0);(9,6);(9,0)|]
           |]

// L-shaped 12x12 grid
let Ltest = 
           [|
            [|(10,4);(10,0);(0,0);(0,4)|]
            [|(3,5);(0,5);(0,11);(3,11)|]
           |]

(* in FSI, enter: 
#I "E:\Users\Wang\Desktop\\2011summ\dnaresearch\detwords\RectLibrary\RectLibrary\\bin\Debug";;
#r "RectLibrary.dll";;
#r "DNAWordLibrary.dll";; *)

let seperateTopRight (vertices : (int*int)[]) =
    let minX = vertices |> Array.map (fun tuple -> fst tuple) |> Array.min
    let maxX = vertices |> Array.map (fun tuple -> fst tuple) |> Array.max
    let maxY = vertices |> Array.map (fun tuple -> snd tuple) |> Array.max
    let mutable ListToBreak = vertices
    let cornerBR = vertices |> Array.maxBy (fun tuple -> (fst tuple) * maxX + snd tuple)
    let mutable top = [| |]
    let mutable bottom = [| |]

    let mutable stopT = false
    let mutable stopB = false

    //for i = minX to maxX do
    while not (stopT && stopB) do
        let list = ListToBreak
            
        if not stopB then
            let testY = ([| 0 .. list.Length - 1 |] |> Array.sortBy (fun i -> fst list.[i] + (snd list.[i]) * maxY)).[0]
            bottom <- Array.append bottom [| list.[testY] |]
            if list.[testY] = cornerBR then stopB <- true
            ListToBreak <- Array.append list.[0 .. testY - 1] list.[testY + 1 .. list.Length - 1]
        if not stopT then
            let testX = ([| 0 .. list.Length - 1 |] |> Array.sortBy (fun i -> (fst list.[i]) * maxX + snd list.[i])).[0]
            printfn "%d" testX
            printfn "%A" list
            top <- Array.append top [| list.[testX] |]
            if list.[testX] = cornerBR then stopT <- true
            ListToBreak <- Array.append list.[0 .. testX - 1] list.[testX + 1 .. list.Length - 1]           
    [| top; bottom |]

let inputBinMatrix = array2D [ [1; 1]; [1; 1] ]

// determine threshold (0, 10, etc)
let threshold = 0

// find the vertices
let vertices = findVertices.VertexFind inputBinMatrix
printfn "%A" vertices
// let concaveVerts = findVertices.ConcaveVertexFind inputBinMatrix

// gift-wrap the vertices
let giftVerts = producePolygon.giftWrap vertices threshold

// rectangulate the shape
let rects = RectangulateOld.RectangulateOld giftVerts inputBinMatrix

// tile the rectangles
// let tiles = tilingTools.createTiles (tilingTools.sortVertices [|[|(0,0);(0,2);(2,2);(2,0)|]|]);;
let tiles = tilingTools.createTiles (tilingTools.sortVertices rects)

// produce an array of tuples from the input and incoming coordinate
let updateTile (tileID : string) (listTiles : (int * int)[]) =
    let delimIndex = tileID.IndexOf 'x'
    let x = int tileID.[1..(delimIndex-1)]
    let y = int tileID.[(delimIndex+1)..]
    // in order to append, listTiles can't be null
    let newlist = Array.append listTiles [|(x,y)|]
    newlist

// remove the incoming coordinate from the array of tuples
let removeTile (tileID : string) (listTiles : (int * int)[]) =
    let delimIndex = tileID.IndexOf 'x'
    let x = int tileID.[1..(delimIndex-1)]
    let y = int tileID.[(delimIndex+1)..]
    // find the index of the tile to remove
    let tileIndex = Array.findIndex (fun elem -> (fst elem = x) && (snd elem = y)) listTiles
    // remove the tile
    let newlist = Array.append listTiles.[0..(tileIndex-1)] listTiles.[(tileIndex+1)..]
    newlist

// produce a binary matrix from an unsorted array of (x,y) coordinates
let produceBinMatrix (listTiles : (int * int)[]) =
    // get our minimum and maximum values
    let minX = listTiles |> Array.map (fun tuple -> fst tuple) |> Array.min
    let minY = listTiles |> Array.map (fun tuple -> snd tuple) |> Array.min
    let maxX = listTiles |> Array.map (fun tuple -> fst tuple) |> Array.max
    let maxY = listTiles |> Array.map (fun tuple -> snd tuple) |> Array.max
    // define the size of the bin matrix, this way it doesn't matter where we started on the grid
    let sizeX = maxX - minX + 1
    let sizeY = maxY - minY + 1
    // let emptybinMatrix = Array2D.zeroCreate sizeX sizeY
    // let's re-map ALL of the tuples so that our numbers start at 0 rather than whichever the minimum was
    let newTiles = listTiles |> Array.map (fun tuple -> (((fst tuple)-minX),((snd tuple)-minY)))
    // now let's map it so that the ones that exist in newTiles = 1 on the binMatrix
    // ** FIND A FUNCTIONAL WAY TO DO THIS LATER, probably using 'when'
    let mutable binMatrix = Array2D.zeroCreate sizeX sizeY
    for i = 0 to (newTiles.Length-1) do
        let currX = fst newTiles.[i]
        let currY = snd newTiles.[i]
        binMatrix.[currX,currY] <- 1
    done
    //let binMatrix = Array2D.map (fun elem -> (emptybinMatrix.[(fst elem),(snd elem)] <- 1)) newTiles
    binMatrix

// if we need to run this all at once, we call this function
let produceTiles (inputBinMatrix : int [,]) (threshold : int) =
    let vertices = findVertices.VertexFind inputBinMatrix
    let giftVerts = producePolygon.giftWrap vertices threshold
    let rects = RectangulateOld.RectangulateOld giftVerts inputBinMatrix
    let tilesWithInfo = tilingTools.createTiles (tilingTools.sortVertices rects)
    tilesWithInfo

// if we need to run this all at once, but with auto-rect
let produceAutoTiles (inputBinMatrix : int [,]) =
    printf "rectangulating"
    let rects = Rectangulate.Rectangulate inputBinMatrix
    printf "creating tiles"
    let tilesWithInfo = tilingTools.createTiles (tilingTools.sortVertices rects)
    tilesWithInfo

let produceVertArray (vertsIn : string) =
    // vertsIn has the style: "x1,y1;x2,y2;x3,y3;...etc"
    let mutable commaIndices = [||]
    let mutable semiIndices = [|0|]
    for i = 0 to (vertsIn.Length - 1) do
        if vertsIn.[i] = ',' then
            commaIndices <- Array.append commaIndices [|i|]
        elif vertsIn.[i] = ';' then
            semiIndices <- Array.append semiIndices [|i|]
    done
    // now that we know where everything is, we can go in the order that everything up 
    // to a comma is an x-value, and everything from comma to semi-colon is a y-value!
    let mutable coordArray = [||]
    // (TODAY): BEGIN A FOR LOOP THAT USES THE INDICES OF commaIndices (since # of commas = # of semi-colons)
    // THEN IT IS EASY TO GET X AND Y
    // so we can do Xs (between ; and,), then do Ys(between , and ;), then initialize them together for a final coordArray
    for i = 1 to commaIndices.Length-1 do
        let currX = int vertsIn.[(semiIndices.[i-1])..commaIndices.[i-1]]
        let currY = int vertsIn.[(commaIndices.[i-1])..semiIndices.[i]]
        let tempVert = [|(currX, currY)|]
        coordArray <- Array.append coordArray tempVert
    done
    coordArray

let produceTilefromVertArray (giftVerts : (int * int)[]) (inputBinMatrix : int [,]) =
    let rects = RectangulateOld.RectangulateOld giftVerts inputBinMatrix
    let tilesWithInfo = tilingTools.createTiles (tilingTools.sortVertices rects)
    tilesWithInfo

    (*
    let tiles = tilesWithInfo.[0..(tilesWithInfo.Length-2)]
    let nA = int tilesWithInfo.[(tilesWithInfo.Length-1)].[2]
    let nB = int tilesWithInfo.[(tilesWithInfo.Length-1)].[4]
    let nF = int tilesWithInfo.[(tilesWithInfo.Length-1)].[6]
    let stats = tilesWithInfo.[tilesWithInfo.Length-1]
    printf "%A\n" stats
    let tableMap = produceOutput.produceTableMap tiles
    tableMap*)